-
Notifications
You must be signed in to change notification settings - Fork 171
C/LLVM: Fixes with dict get #1700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
integration_tests/CMakeLists.txt
Outdated
| RUN(NAME test_dict_09 LABELS cpython llvm c) | ||
| RUN(NAME test_dict_10 LABELS cpython llvm) # TODO: Add support of dict with string in C backend | ||
| RUN(NAME test_dict_10 LABELS cpython llvm) # TODO: Add support of dict with string in C backend | ||
| RUN(NAME test_dict_11 LABELS cpython c) # TODO: Add LLVM support |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't move ahead without enabling LLVM backend for any test. Please make it work with LLVM before C.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point, the LLVM backend is a "lowering" backend, so it ensures our design is good. The C/C++/Julia backends are high level backends, so they don't reveal all issues. WASM is also a lowering backend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that sounds right. Thanks, I fixed it.
|
Did some testing on this branch. The default value should only be considered when the key is not present in the dictionary. |
|
Also another strange case I came across - So should be made robust and tested that it does not give key error sometimes when key is not present in the dictionary. This might be a possible case of #1593 in |
6249f49 to
c935c96
Compare
src/libasr/codegen/llvm_utils.cpp
Outdated
| std::pair<std::string, std::string> llvm_key = std::make_pair( | ||
| ASRUtils::get_type_code(key_asr_type), | ||
| ASRUtils::get_type_code(value_asr_type) | ||
| ); | ||
| llvm::Type* value_type = std::get<2>(typecode2dicttype[llvm_key]).second; | ||
| llvm::Value* result = builder->CreateAlloca(value_type, nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think result should only be allocated when def_value is not nullptr. I think you should not mix read_item with the logic of dict.get. Make a new method get_item and call it to implement dict.get. Direct access via [] should be done by read_item (which should be left untouched in this PR).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presently, [] and dict.get are implemented with the same DictItem node in the ASR and we can re-use the same implementation just to extend it with default. I am not sure if it is a good idea to re-implement the same logic for get_item and read_item which effectively are doing the same job.
I think
resultshould only be allocated whendef_valueis notnullptr.
It's also used on line 1597 which also makes it more generalized in the case when key_hash is matching but not the keys. This was the bug with the previous implementation where it raised an error for the case where key_hash matches but not the key while it didn't raise any error when the key is totally absent. This is also fixed using the current PR. So, I don't think separating two methods for implementing same logic is a good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well in this PR itself we have seen (as pointed in #1700 (comment) and #1700 (comment)) how read_item is also affected when you implement dict.get inside it. So de-coupling if-else-if checks
I am not sure if it is a good idea to re-implement the same logic for
get_itemandread_itemwhich effectively are doing the same job.
If code repetition is the issue then you can solve it by using a macro, or a utility method and call it from read_item and get_item.
Presently,
[]anddict.getare implemented with the sameDictItemnode in the ASR and we can re-use the same implementation just to extend it with default
Won't be the case very soon. We will use IntrinsicFunction to implement, dict.item and dict.get separately.
It's also used on line 1597 which also makes it more generalized in the case when key_hash is matching but not the keys.
In https://github.com/lcompilers/lpython/blob/c935c96b50abeb0553213904a9f96247f6f78421/src/libasr/codegen/llvm_utils.cpp, AFAICT, its only used when def_value != nullptr,
lpython/src/libasr/codegen/llvm_utils.cpp
Lines 1596 to 1598 in c935c96
| if (def_value != nullptr) { | |
| LLVM::CreateStore(*builder, LLVM::CreateLoad(*builder, def_value), result); | |
| } else { |
Again, my POV is still the same read_item and get_item should be different methods. However they can call common utility methods or macros to execute the common logic. if (some_arg_is_present) and then else always indicate that de-coupling is needed.
This was the bug with the previous implementation where it raised an error for the case where key_hash matches but not the key while it didn't raise any error when the key is totally absent.
Please add a test for it and fix the read_item and get_item methods accordingly.
ba6af20 to
46cde59
Compare
czgdp1807
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Before merging, please ensure our dict benchmarks don't degrade due to this PR.
Slight changes are expected because of an extra if-else check in the last commit which was a bug. |
src/libasr/codegen/llvm_utils.cpp
Outdated
| }); | ||
| llvm::Value* item = llvm_utils->list_api->read_item(value_list, pos, | ||
| false, module, true); | ||
| false, module, true);; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should only happen in safe or debug modes of LPython. In fast mode one shouldn't catch these kind of errors. See, #1139.
I think following the same pattern as raising index errors in lists should work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, updated this with even dedicated methods for default and bound checking which leaves the original method untouched (removed some if-else checks) and so its performance will be >= existing performance.
No description provided.